#!/bin/bash
# 系统配置总控
# author    : guyadong
# date      : 2019/07/30
# 脚本初始化
. ./common_init.sh

# 获取发行版本(ubuntu,centos...)
[ -f /etc/os-release ] || exit_on_error "ERROR:NOT FOUND /etc/os-release"
eval dist_id=$(get_value /etc/os-release ID)
. ./native_functions_${dist_id,,}.sh || exit_on_error "不支持当前平台:$dist_id"

function fun_java8_installed(){
    java_installed=1
    jdk8_available "$java_exe" && java_installed=0 && context_java_configured=0 && return $context_last_code

    local init_folder="$HOME"
    [ -e "$java_exe" ] && init_folder="$(dirname $java_exe)"
    local code=0
    local defaultno=    
    [ "$java_installed" = 1 ] && defaultno='--defaultno'
    
    while true
    do
        dialog  --backtitle "$DEFAULT_BACK_TITLE$context_backtitle_suffix" $DLG_YESNO_LABEL \
                --title 'java 配置' $DLG_BACK_BTN $defaultno \
                --yesno "java 8 是否安装?" 5 30
        # 点击'返回'则退出循环
        code=$?
        [ $code -lt 2 ] && java_installed=$code
        [ $code -gt 0 ] && return $code 
        # 保存对话框选项的值到 $folder,如果对话框选项返回,则 $folder 值为'EXIT_$?'
        local folder=$(dialog  --backtitle "$DEFAULT_BACK_TITLE$context_backtitle_suffix" \
                --title "指定 java 安装路径" $DLG_BACK_BTN --nocancel \
                --dselect $init_folder 7 40 \
                3>&1 1>&2 2>&3 || echo EXIT_$?)
        [[ "$folder" =~ EXIT_[0-9] ]] && continue
        # 判断是否为 java 安装文件夹,是则退出循环否则报错并继续循环
        jdk8_available "$folder/java" && java_installed=0 && context_java_configured=0 && java_exe="$folder/java" && return 0
        error_message '所选文件夹不是 java 8 安装路径'
        continue
    done
}

function fun_node_installed(){
    node_installed=1
    node_available "$node_exe" && node_installed=0 && return $context_last_code

    local init_folder="$HOME"
    [ -e "$node_exe" ] && init_folder="$(dirname $node_exe)"
    local code=0
    local defaultno=    
    [ "$node_installed" -ne 0 ] && defaultno='--defaultno'

    while true
    do
        dialog  --backtitle "$DEFAULT_BACK_TITLE$context_backtitle_suffix" $DLG_YESNO_LABEL \
                --title 'node 配置' $DLG_BACK_BTN $defaultno \
                --yesno "node 是否安装?" 5 30
        # 点击'返回'则退出循环
        code=$?
        [ $code -lt 2 ] && node_installed=$code
        [ $code -gt 0 ] && return $code 
        # 保存对话框选项的值到 $folder,如果对话框选项返回,则 $folder 值为'EXIT_$?'
        local folder=$(dialog  --backtitle "$DEFAULT_BACK_TITLE$context_backtitle_suffix" \
                --title "指定 node 安装路径" $DLG_BACK_BTN --nocancel \
                --dselect $init_folder 7 40 \
                3>&1 1>&2 2>&3 || echo EXIT_$?)
        [[ "$folder" =~ EXIT_[0-9] ]] && continue
        # 判断是否为 node 安装文件夹,是则退出循环否则报错并继续循环
        node_available "$folder/node" && node_installed=0 && node_exe="$folder/node" && return 0
        error_message '所选文件夹不是 node 安装路径'
        continue
    done
}

function fun_confirm_config(){
    context_backtitle_suffix=''
    local str=
    if [ "$facelog_install" = 'on' ] 
    then
        str="$str\nfacelog 服务配置:"
        str="$str\nroot密码:$facelog_root_pwd"
        str="$str\nport:$facelog_port"
        str="$str\n数据库连接参数"
        str="$str\nurl:$(facelog_jdbc_url)"
        str="$str\nusername=$database_jdbc_username"
        str="$str\nusername=$database_jdbc_password"
        if [ "$faceapi_service_enable" -eq 0 ]
        then
            str="$str\n绑定FaceApi服务"
            str="$str\nfaceapi host=$faceapi_service_host"
            str="$str\nfaceapi port=$faceapi_service_port"
            str="$str\nsdkversion=$faceapi_service_sdkversion"
        fi
        if [ "$proxy_service_enable" -eq 0 ]
        then
            str="$str\n启动erpc proxy 服务:"
            str="$str\nport:$proxy_port"
            str="$str\nexe :$proxy_exe"
        fi
    else
        str="$str\nfacelog 服务:off"
    fi

    str="$str\nredis 连接配置:"
    str="$str\nURI:$(make_redis_uri)"
    if [ "$webredis_install" = 'on' ] 
    then
        str="$str\nwebredis 服务配置:"
        str="$str\nport:$webredis_port"  
    else
        str="$str\nwebredis 服务:off"      
    fi
    if [ "$mq_type" = "ACTIVEMQ" ]
    then
        str="$str\n消息系统配置:"        
        str="$str\n消息系统类型:$mq_type"
        str="$str\nAMQP连接:$(make_activemq_uri true)"
        str="$str\nMQTT连接:$(make_activemq_mqtt_uri true)"
        str="$str\nWS连接:$(make_activemq_ws_uri true)"
    fi
    if [ "$fdevmgr_install" = 'on' ] 
    then
        str="$str\nfdevmgr 服务配置:"
        str="$str\nport:$fdevmgr_port"
        str="$str\n数据库连接参数"
        str="$str\nurl:$(fdevmgr_jdbc_url)"
        str="$str\nusername=$fdevmgr_db_username"
        str="$str\nusername=$fdevmgr_db_password"  
        str="$str\nsocketIp:$fdevmgrweb_wrhost"
        str="$str\nfdevmgrweb_selfaddress:$fdevmgrweb_selfaddress"
        if [ $webredis_use_local -ne 0 ]     
        then
            str="$str\nwebredis.port=$webredis_port"
        fi
    else
        str="$str\nfdevmgr 服务:off" 
    fi
    dialog --backtitle "$DEFAULT_BACK_TITLE$context_backtitle_suffix$context_backtitle_suffix" \
            --title '确认配置' $DLG_BACK_BTN --nocancel \
            --msgbox "请确认如下参数配置是否正确:$str" 0 0
}

# 选择使用的消息系统类型 
function fun_message_queue_type(){
    [ -n "$mq_type_selected" ] && return 0
    local redis_selected=off
    local activemq_selected=off
    # mq_type 未定义时使用REDIS为默认值
    [ -z "$mq_type" ] && mq_type=REDIS
    [ "$mq_type" = "REDIS" ] && redis_selected=on
    [ "$mq_type" = "ACTIVEMQ" ] && activemq_selected=on
    mq_type=$(dialog \
        --backtitle "$DEFAULT_BACK_TITLE$context_backtitle_suffix" \
        --title "Message Queue Service(消息系统类型)" --nocancel \
        --radiolist  '请选择使用的消息系统类型:' 12 60 0 \
        'REDIS' '基于Redis实现的消息服务' $redis_selected \
        'ACTIVEMQ' 'Activemq提供的消息服务(支持MQTT)' $activemq_selected \
        3>&1 1>&2 2>&3 || echo EXIT_$?)
    [[ "$mq_type" =~ EXIT_[0-9] ]] && return ${mq_type##*EXIT_}
    mq_type_selected=ON
    return 0
}

# 选择要安装的组件 
function fun_start_cfg(){
    fun_message_queue_type
    
    [ $mq_type = "REDIS" ] && service_selected=$(dialog \
        --backtitle "$DEFAULT_BACK_TITLE$context_backtitle_suffix" \
        --title "starting" \
        --cancel-label "退出" \
        --checklist  '请选择要安装的组件:' 12 60 0 \
        'facelog' 'facelog 核心服务' $facelog_install \
        'webredis' '用于web前端订阅redis消息的支持服务' $webredis_install \
        'fdevmgr' '设备管理应用端服务' $fdevmgr_install \
        3>&1 1>&2 2>&3 || echo EXIT_$?)
    [ $mq_type != "REDIS" ] && webredis_install=OFF && service_selected=$(dialog \
        --backtitle "$DEFAULT_BACK_TITLE$context_backtitle_suffix" \
        --title "starting" \
        --cancel-label "退出" \
        --checklist  '请选择要安装的组件:' 12 60 0 \
        'facelog' 'facelog 核心服务' $facelog_install \
        'fdevmgr' '设备管理应用端服务' $fdevmgr_install \
        3>&1 1>&2 2>&3 || echo EXIT_$?)
    [[ "$service_selected" =~ EXIT_[0-9] ]] && return ${service_selected##*EXIT_}
    for n in facelog webredis fdevmgr ; do eval "${n}_install=off"; done
    for n in $service_selected ; do eval "${n}_install=on"; done    
    return 0
}
function exit_or_install(){    
    dialog  --backtitle "$DEFAULT_BACK_TITLE$context_backtitle_suffix" \
            --ok-label "现在安装" --cancel-label "稍后安装" \
            --yesno "系统配置已经完成，系统参数配置已经保存到 ./status 文件中，\n现在是否执行安装?\n您可以稍后手工执行./install.sh完成安装" 0 0
}
function init_frame_list(){
    context_backtitle_suffix=
    local array=($service_selected)
    for i in $(seq 1 $(expr ${#array[@]} - 1))
    do
        local n=${array[i]}
        local name=${n^^}_BEGIN
        local l=${array[$(expr $i - 1)]}
        eval ${l^^}_END[0]=$name
        if [ $i -eq $(expr ${#array[@]} - 1) ]
        then
            eval ${n^^}_END[0]=LAST_CONFIRM
        fi
    done
}

function reset_context(){    
    # 上一帧返回的状态,0|1:前进(可能有分支判断), 3:后退到前一帧
    context_last_code=0
    # 是否已经完成了指定组件的配置
    # mysql 是否已经配置
    context_mysql_configured=1
    # 已经配置的 mysql 连接参数
    context_mysql_host=
    context_mysql_port=
    context_mysql_username=
    context_mysql_password=
    context_mysql_schema=
    # redis 是否已经配置
    context_redis_configured=1
    # activemq 是否已经配置
    context_activemq_configured=1
    # facelog RPC服务是否已经配置
    context_facelog_service_configured=1
    # erpc proxy服务是否已经配置
    context_proxy_service_configured=1
    context_java_configured=1
    context_node_configured=1

    # 本地 facelog 服务是否配置
    context_facelog_configure=1
    # 本地 webredis 服务是否配置
    context_webredis_configure=1
    # 本地 fdevmgr 服务是否配置
    context_fdevmgr_configure=1

    frame_queue=()
    context_backtitle_suffix=
}

function start_frame_flow(){
    local array=($service_selected)
    [ ${#array[@]} -eq 0 ] && return 0
    local first=${array[0]}
    name=${first^^}_BEGIN
    frame_flow  $name
}

function fun_mq_use_local(){
    # 使用redis时直接跳过 activemq消息系统配置
    [ $mq_type = "REDIS" ] && return 4
    fun_activemq_use_local
}

function fun_fdevmgr_webredis_cfg(){
    [ $webredis_use_local -eq 0 ] && [ $context_last_code -ne 4 ] && return $context_last_code
    [ $webredis_use_local -eq 0 ] && [ $context_last_code -eq 4 ] && return 0
    webredis_host=$redis_host
    fun_remote_webredis_config
}

function fun_facelog_service_begin(){
    [ $context_facelog_configure -eq 0 ] && return $context_last_code
    [ $context_last_code -eq 3 ] && return $context_last_code
    context_backtitle_suffix="--facelog 服务配置"

    return 0
}
function fun_facelog_service_end(){
    context_backtitle_suffix="--facelog 服务配置"
    [ $context_last_code -eq 3 ] && return $context_last_code
    context_facelog_configure=0
    return 0
}
function fun_webredis_service_begin(){
    context_backtitle_suffix="--webredis 服务配置"
    [ $context_last_code -eq 3 ] && return $context_last_code
    [ $context_webredis_configure -eq 0 ] && return 4
    return 0
}
function fun_webredis_service_end(){
    context_backtitle_suffix="--webredis 服务配置"
    [ $context_last_code -eq 3 ] && return $context_last_code 
    context_webredis_configure=0
    webredis_use_local=0
    return 0
}
function fun_fdevmgr_service_begin(){
    [ $context_fdevmgr_configure -eq 0 ] && return $context_last_code
    [ $context_last_code -eq 3 ] && return $context_last_code
    context_backtitle_suffix="--fdevmgr 服务配置"
    return 0
}
function fun_fdevmgr_service_end(){    
    context_backtitle_suffix="--fdevmgr 服务配置"
    [ $context_last_code -eq 3 ] && return $context_last_code
    context_fdevmgr_configure=0    
    return 0
}

# 保存配置状态到文件
function save_status(){
    update_status_value database_use_local
    update_status_value database_reset_tables
    update_status_value database_jdbc_host
    update_status_value database_jdbc_port
    update_status_value database_jdbc_username
    update_status_value database_jdbc_password
    update_status_value database_jdbc_schema
    set_status_value database_jdbc_url "$(facelog_jdbc_url)"

    update_status_value fdevmgr_db_use_local
    update_status_value fdevmgr_db_reset_tables
    update_status_value fdevmgr_port
    update_status_value fdevmgr_db_host
    update_status_value fdevmgr_db_port
    update_status_value fdevmgr_db_username
    update_status_value fdevmgr_db_password
    update_status_value fdevmgr_db_schema
    set_status_value fdevmgr_db_url "$(fdevmgr_jdbc_url)"

    update_status_value redis_use_local
    update_status_value redis_host
    update_status_value redis_port
    update_status_value redis_password
    update_status_value redis_database
    update_status_value redis_uri

    update_status_value webredis_use_local
    update_status_value webredis_host
    update_status_value webredis_port

    update_status_value activemq_use_local
    update_status_value activemq_host
    update_status_value activemq_port
    update_status_value activemq_mqtt_port
    update_status_value activemq_ws_port
    update_status_value activemq_username
    update_status_value activemq_password

    update_status_value mq_type

    update_status_value nginx_local_installed
    update_status_value nginx_location
    update_status_value nginx_port

    update_status_value faceapi_service_enable
    update_status_value faceapi_service_host
    update_status_value faceapi_service_port
    update_status_value faceapi_service_sdkversion

    update_status_value proxy_service_enable
    update_status_value facelog_host
    update_status_value facelog_port
    update_status_value facelog_root_pwd

    update_status_value proxy_exe
    update_status_value proxy_port

    update_status_value fdevmgrweb_wrhost
    update_status_value fdevmgrweb_selfaddress
    update_status_value fdevmgrweb_upload_folder

    update_status_value node_installed
    update_status_value node_exe

    update_status_value java_installed
    update_status_value java_exe
    
    update_status_value facelog_install
    update_status_value webredis_install
    update_status_value fdevmgr_install

    update_status_value sudo_pwd
}
###### 服务流程配置 ######
# 每个 frame 定义一个动作，几个相联的frame定义一个服务单元
# frame 用map定义,map 中成员说明
# fun 执行的函数名
# 0 选择YES，继续前进的frame对象名
# 1 选择NO，继续前进的frame对象名
# 4 跳过服务单元继续前进的frame对象名
############### facelog 服务配置流程定义 <<##################
declare -A FACELOG_BEGIN=([fun]=fun_facelog_service_begin \
                        [0]=FACELOG_USE_LOCAL_DB \
                        )
declare -A FACELOG_USE_LOCAL_DB=([fun]=fun_facelog_db_use_local \
                        [0]=FACELOG_LOCAL_DB_CONFIG \
                        [1]=FACELOG_REMOTE_DB_CONFIG \
                        )

declare -A FACELOG_REMOTE_DB_CONFIG=([fun]=fun_facelog_remote_db_config \
                        [0]=FACELOG_RESET_TABLES\
                        )
declare -A FACELOG_LOCAL_DB_CONFIG=([fun]=fun_facelog_local_db_config \
                        [0]=FACELOG_RESET_TABLES \
                        )
declare -A FACELOG_RESET_TABLES=([fun]=fun_reset_facelog_tables \
                        [0]=FACELOG_USE_LOCAL_REDIS \
                        [1]=FACELOG_USE_LOCAL_REDIS \
                        )
declare -A FACELOG_USE_LOCAL_REDIS=([fun]=fun_redis_use_local \
                        [0]=FACELOG_LOCAL_REDIS_CONFIG \
                        [1]=FACELOG_REMOTE_REDIS_CONFIG \
                        [4]=FACELOG_USE_LOCAL_MQ \
                        )  

declare -A FACELOG_LOCAL_REDIS_CONFIG=([fun]=fun_local_redis_connect \
                        [0]=FACELOG_USE_LOCAL_MQ \
                        )

declare -A FACELOG_REMOTE_REDIS_CONFIG=([fun]=fun_remote_redis_connect \
                        [0]=FACELOG_USE_LOCAL_MQ \
                        )

declare -A FACELOG_USE_LOCAL_MQ=([fun]=fun_mq_use_local \
                        [0]=FACELOG_LOCAL_AMQ_CONFIG \
                        [1]=FACELOG_REMOTE_AMQ_CONFIG \
                        [4]=FACELOG_BIND_FACEAPI \
                        )  

declare -A FACELOG_LOCAL_AMQ_CONFIG=([fun]=fun_local_activemq_connect \
                        [0]=FACELOG_BIND_FACEAPI \
                        )

declare -A FACELOG_REMOTE_AMQ_CONFIG=([fun]=fun_remote_activemq_connect \
                        [0]=FACELOG_BIND_FACEAPI \
                        )

declare -A FACELOG_BIND_FACEAPI=([fun]=fun_bind_faceapi_service \
                        [0]=FACELOG_FACEAPI_CONFIG \
                        [1]=FACELOG_START_PROXY \
                        )  

declare -A FACELOG_FACEAPI_CONFIG=([fun]=fun_local_faceapi_service_connect \
                        [0]=FACELOG_START_PROXY \
                        )

declare -A FACELOG_START_PROXY=([fun]=fun_start_proxy_service \
                        [0]=FACELOG_PROXY_PORT \
                        [1]=FACELOG_JAVA_CONFIG \
                        )  

declare -A FACELOG_PROXY_PORT=([fun]=fun_proxy_service_port \
                        [0]=FACELOG_PROXY_EXE \
                        )  

declare -A FACELOG_PROXY_EXE=([fun]=fun_proxy_service_exe \
                        [0]=FACELOG_JAVA_CONFIG \
                        )  


declare -A FACELOG_JAVA_CONFIG=([fun]=fun_java8_installed \
                        [0]=FACELOG_END \
                        [1]=FACELOG_END \
                        )
declare -A FACELOG_END=([fun]=fun_facelog_service_end                    
                        ) 
############### facelog 配置流程定义 >>##################
############### webredis 配置流程定义 >>##################
declare -A WEBREDIS_BEGIN=([fun]=fun_webredis_service_begin \
                        [0]=WEBREDIS_NODE_INSTALLED \
                        [4]=WEBREDIS_END
                        )

declare -A WEBREDIS_NODE_INSTALLED=([fun]=fun_node_installed \
                        [0]=WEBREDIS_USE_LOCAL_REDIS \
                        [1]=WEBREDIS_USE_LOCAL_REDIS \
                        )

declare -A WEBREDIS_USE_LOCAL_REDIS=([fun]=fun_redis_use_local \
                        [0]=WEBREDIS_LOCAL_REDIS_CONFIG \
                        [1]=WEBREDIS_REMOTE_REDIS_CONFIG \
                        [4]=WEBREDIS_CONFIG \
                        )  

declare -A WEBREDIS_LOCAL_REDIS_CONFIG=([fun]=fun_local_redis_connect \
                        [0]=WEBREDIS_CONFIG \
                        )

declare -A WEBREDIS_REMOTE_REDIS_CONFIG=([fun]=fun_remote_redis_connect \
                        [0]=WEBREDIS_CONFIG \
                        )

declare -A WEBREDIS_CONFIG=([fun]=fun_webredis_config \
                        [0]=WEBREDIS_END \
                        )

declare -A WEBREDIS_REMOTE_CONFIG=([fun]=fun_remote_webredis_config \
                        [0]=WEBREDIS_END \
                        )

declare -A WEBREDIS_END=([fun]=fun_webredis_service_end \
                        )
############### webredis 配置流程定义 <<##################
################fdevmgr 配置流程定义 <<#############
declare -A FDEVMGR_BEGIN=([fun]=fun_fdevmgr_service_begin \
                        [0]=FDEVMGR_CFG \
                        )
declare -A FDEVMGR_CFG=([fun]=fun_fdevmgr_cfg \
                        [0]=FDEVMGR_USE_LOCAL_DB \
                        )
declare -A FDEVMGR_USE_LOCAL_DB=([fun]=fun_fdevmgr_db_use_local \
                        [0]=FDEVMGR_LOCAL_DB_CONFIG \
                        [1]=FDEVMGR_REMOTE_DB_CONFIG \
                        )

declare -A FDEVMGR_REMOTE_DB_CONFIG=([fun]=fun_fdevmgr_remote_db_config \
                        [0]=FDEVMGR_RESET_TABLES\
                        )
declare -A FDEVMGR_LOCAL_DB_CONFIG=([fun]=fun_fdevmgr_local_db_config \
                        [0]=FDEVMGR_RESET_TABLES \
                        )
declare -A FDEVMGR_RESET_TABLES=([fun]=fun_reset_fdevmgr_tables \
                        [0]=FDEVMGR_USE_LOCAL_REDIS \
                        [1]=FDEVMGR_USE_LOCAL_REDIS \
                        )
declare -A FDEVMGR_USE_LOCAL_REDIS=([fun]=fun_redis_use_local \
                        [0]=FDEVMGR_LOCAL_REDIS_CONFIG \
                        [1]=FDEVMGR_REMOTE_REDIS_CONFIG \
                        [4]=FDEVMGR_USE_LOCAL_MQ \
                        )  

declare -A FDEVMGR_REMOTE_REDIS_CONFIG=([fun]=fun_remote_redis_connect \
                        [0]=FDEVMGR_USE_LOCAL_MQ \
                        )
declare -A FDEVMGR_LOCAL_REDIS_CONFIG=([fun]=fun_local_redis_connect \
                        [0]=FDEVMGR_USE_LOCAL_MQ \
                        )

declare -A FDEVMGR_USE_LOCAL_MQ=([fun]=fun_mq_use_local \
                        [0]=FDEVMGR_LOCAL_AMQ_CONFIG \
                        [1]=FDEVMGR_REMOTE_AMQ_CONFIG \
                        [4]=FDEVMGR_WEBREDIS_CONFIG \
                        )  

declare -A FDEVMGR_LOCAL_AMQ_CONFIG=([fun]=fun_local_activemq_connect \
                        [0]=FDEVMGR_WEBREDIS_CONFIG \
                        )

declare -A FDEVMGR_REMOTE_AMQ_CONFIG=([fun]=fun_remote_activemq_connect \
                        [0]=FDEVMGR_WEBREDIS_CONFIG \
                        )

declare -A FDEVMGR_WEBREDIS_CONFIG=([fun]=fun_fdevmgr_webredis_cfg \
                        [0]=FDEVMGR_WEB_CONFIG \
                        )
declare -A FDEVMGR_WEB_CONFIG=([fun]=fun_fdevmgrweb_selfaddr_cfg \
                        [0]=FDEVMGR_UPLOAD_FOLDER_CONFIG \
                        )
declare -A FDEVMGR_UPLOAD_FOLDER_CONFIG=([fun]=fun_fdevmgr_upload_folder_cfg \
                        [0]=FDEVMGR_JAVA_CONFIG \
                        )


declare -A FDEVMGR_JAVA_CONFIG=([fun]=fun_java8_installed  \
                        [0]=FDEVMGR_END \
                        [1]=FDEVMGR_END \
                        )
declare -A FDEVMGR_END=([fun]=fun_fdevmgr_service_end                    
                        ) 
################fdevmgr 配置流程定义 >>###############
################配置确认 <<#######################
declare -A LAST_CONFIRM=([fun]=fun_confirm_config) 
################配置确认 >>#######################
install_base_utils
chedk_supported_os

check_sudo_user

rm -f frame_flow.log

while true
do
    reset_context
   
    fun_start_cfg || exit 255

    init_frame_list

    start_frame_flow
    [ $context_last_code -eq 0 ] && break;

done

save_status

exit_or_install && ./install.sh
